/*!
 *  \file       SimpleMatrix.cpp
 *  \brief      Implementazione della classe \c SimpleMatrix
 *  \author     Davide Scola <S2299453@studenti.unige.it>
 *  \author	Minetti Alberto <S3064777@studenti.unige.it>
 *  \version    1.0
 */
#include <vector>
#include <algorithm>
#include "SimpleMatrix.hpp"
#include "BadIndexException.hpp"
#include "InvalidSizeException.hpp"

using namespace std;


/*!
 *  \brief      Costruttore di copia di \c SimpleMatrix
 *  \param[in]	other	matrice da copiare
 */
template < class tType > inline
SimpleMatrix< tType >::SimpleMatrix( SimpleMatrix const& other )
  : rows_ ( other->rows )
  , cols_ ( other->cols )
{
  this->data_ = other->data_;
}

/*!
 *  \brief      Costruttore di \c SimpleMatrix
 *  \param[in]	rows	il numero di righe
 *  \param[in]	cols	il numero di colonne
 *
 *  \exception InvalidSizeException	se almeno una delle due dimensioni e` nulla
 */
template < class tType > inline
SimpleMatrix< tType >::SimpleMatrix( unsigned int rows, unsigned int cols )
  : rows_ ( rows )
  , cols_ ( cols )
{
   if( rows == 0 || cols == 0 ) {
     throw InvalidSizeException( );
   }
   
   this->data_.resize( rows * cols );
}

/*!
 *  \brief      Getter per \c rows_
 *  \return	il numero di righe della matrice
 */
template < class tType > inline unsigned int const&
SimpleMatrix< tType >::getRows( void ) const
{
  return this->rows_;
}

/*!
 *  \brief      Getter per \c rows_
 *  \return	il numero di colonne della matrice
 */
template < class tType > inline unsigned int const&
SimpleMatrix< tType >::getCols( void ) const
{
  return this->cols_;
}

/*!
 *  \brief      Ritorna il valore massimo all'interno della matrice
 */
template < class tType > inline tType
SimpleMatrix< tType >::findMax ( void ) const
{
  return *max_element( this->data_.begin(), this->data_.end() );
}

/*!
 *  \brief      Operatore di assegnazione della classe \c SimpleMatrix
 *  \param[in]	other	matrice da copiare
 */
template < class tType > inline SimpleMatrix< tType >&
SimpleMatrix< tType >::operator= ( SimpleMatrix const& other )
{
  this->rows_ = other->rows_;
  this->cols_ = other->cols_;
  this->data_ = other->data_;
}

/*!
 *  \brief	Operatore di indicizzazione per la classe \c SimpleMatrix
 *  \param[in]	row	indice di riga
 *  \param[in]	col	indice di colonna
 *
 *  \exception	BadIndexException	se uno dei due indici e` maggiore della dimensione
 */
template < class tType > inline tType&
SimpleMatrix< tType >::operator() ( unsigned int row, unsigned int col)
{
  if( row < this->rows_ && col < this->cols_ ) {
    return this->data_[ this->cols_ * row + col ];
  }
  
  throw BadIndexException( );
}

/*!
 *  \brief	Operatore di indicizazzione per la classe \c SimpleMatrix
 *  \param[in]	row	indice di riga
 *  \param[in]	col	indice di colonna
 *
 *  \exception	BadIndexException	se uno dei due indici e` maggiore della dimensione
 */
template < class tType > inline tType
SimpleMatrix< tType >::operator() ( unsigned int row, unsigned int col) const
{
  if( row < this->rows_ && col < this->cols_ ) {
    return this->data_[ this->cols_ * row + col ];
  }
  
  throw BadIndexException( );
}

/*!
 *  \brief      Restituisce la riga di indice richiesto
 *  \param[in]	index	indice di riga
 *  \param[out]	row	vettore che conterra` la riga
 *
 *  \return	vettore che conterra` la riga
 *
 *  \exception	BadIndexException	se \c index e` maggiore del numero di righe della matrice
 */
template < class tType > std::vector< tType > &
SimpleMatrix< tType >::rowAt( unsigned int index, std::vector< tType > &row )
{
  row.resize( this->cols_ );
  
  for( unsigned int iCol = 0; iCol < this->cols_; ++iCol )
    row[ iCol ] = (*this)( index, iCol );
  
  return row;
}

/*!
 *  \brief      Restituisce la colonna di indice richiesto
 *  \param[in]	index	indice di colonna
 *  \param[out]	column	vettore che conterra` la colonna
 *
 *  \return	vettore che conterra` la colonna
 *
 *  \exception	BadIndexException	se \c index e` maggiore del numero di colonne della matrice
 */
template < class tType > std::vector< tType > &
SimpleMatrix< tType >::colAt( unsigned int index, std::vector< tType > &column )
{
  column.resize( this->rows_ );
  
  for( unsigned int iRow = 0; iRow < this->rows_; ++iRow )
    column[ iRow ] = (*this)( iRow, index );
  
  return column;
}

/*!
 *  \brief      Assegna la riga di indice richiesto
 *  \param[in]	index	indice di riga
 *  \param[in]	row	vettore che contiene la riga
 *
 *  \exception	InvalidSizeException	se la dimensione di \c row non corrisponde
 *					a quella di una riga della matrice
 *  \exception	BadIndexException	se \c index e` maggiore del numero di righe
 *					della matrice
 */
template < class tType > void
SimpleMatrix< tType >::assignRow( unsigned int index, const std::vector< tType > &row )
{
  if( this->cols_ != row.size() ) {
    throw InvalidSizeException( );
  }
  
  for( unsigned int iCol = 0; iCol < this->cols_; ++iCol )
     (*this)( index, iCol ) = row[ iCol ];
}

/*!
 *  \brief      Assegna la colonna di indice richiesto
 *  \param[in]	index	indice di colonna
 *  \param[in]	column	vettore che contiene la colonna
 *
 *  \exception	InvalidSizeException	se la dimensione di \c column non corrisponde
 *					a quella di una colonna della matrice
 *  \exception	BadIndexException	se \c index e` maggiore del numero di colonne
 *					della matrice
 */
template < class tType > void
SimpleMatrix< tType >::assignCol( unsigned int index, const std::vector< tType > &column )
{
  if( this->rows_ != column.size() ) {
    throw InvalidSizeException( );
  }
  
  for( unsigned int iRow = 0; iRow < this->rows_; ++iRow )
     (*this)( iRow, index ) = column[ iRow ];
}

/*!
 *  \brief      Applica l'operazione data a tutta la matrice
 *  \param[in]	operation	operazione da applicare
 */
template < class tType > void
SimpleMatrix< tType >::applyOperator( const callback_t operation )
{
  if( operation != NULL ) {
    (*operation)( *this );
  }
}
